---
title: 빠른 시작
version: 1
---

이 섹션은 [Provider] 패키지에 익숙한 분들 중 Riverpod에 대해 자세히 알고 싶은 분들을 위해 만들어졌습니다.

무엇보다도 먼저 짧은 [시작하기] 글을 읽고 작은 [sandbox] 예제를 통해 Riverpod의 기능을 테스트해 보세요. 
그 결과 마음에 든다면 마이그레이션을 확실히 고려해야 합니다.

실제로 Provider에서 Riverpod로 마이그레이션하는 것은 매우 간단합니다.  

마이그레이션은 기본적으로 *단계적* 방식으로 수행할 수 있는 몇 가지 단계로 구성됩니다.

## `ChangeNotifierProvider`로 시작하기

Riverpod로 전환하는 동안 'ChangeNotifier'를 계속 사용하고, 최신의 멋진 기능을 최대한 빨리 사용하지 않는 것도 상관없습니다.
  
실제로 다음과 같이 시작해도 좋습니다:

```dart
// 아래와 같은 코드를 가지고 있다면
class MyNotifier extends ChangeNotifier {
  int state = 0;

  void increment() {
    state++;
    notifyListeners();
  }
}

// ... 이것만 추가하세요!
final myNotifierProvider = ChangeNotifierProvider<MyNotifier>((ref) {
  return MyNotifier();
});
```

보시다시피 Riverpod은 pkg:Provider에서 마이그레이션을 지원하기 위해 제공되는 [ChangeNotifierProvider] 클래스를 노출합니다.

이 Provider는 새 코드를 작성할 때 권장되지 않으며, Riverpod을 사용하는 가장 좋은 방법은 아니지만
마이그레이션을 시작하는 부드럽고 매우 쉬운 방법이라는 점에 유의하세요.

:::tip
'ChangeNotifier'를 더 최신의 [Riverpod의 provider들]로 '즉시' 변경하려고 서두를 필요는 없습니다.
일부는 약간의 패러다임 전환이 필요하기 때문에 처음에는 어려울 수 있습니다.  

먼저 Riverpod에 익숙해지는 것이 중요하므로 천천히 하세요;
pkg:provider의 *거의* 모든 Provider가 pkg:riverpod에 엄격하게 대응한다는 것을 금방 알 수 있습니다.
:::

## *잎사귀(leaves)*부터 시작

다른 것에 의존하지 않는 Provider, 즉 종속성 트리의 *잎사귀(leaves)*부터 시작하세요.  
모든 잎사귀를 마이그레이션한 후에는 잎사귀에 의존하는 Provider로 이동할 수 있습니다.

다시 말해, 처음부터 `ProxyProvider`를 마이그레이션하지 말고, 모든 종속성을 마이그레이션한 후에 처리하세요.

이렇게 하면 마이그레이션 프로세스가 향상되고 간소화되는 동시에 오류를 최소화/추적할 수 있습니다.


## Riverpod과 Provider가 공존할 수 있습니다.
*Provider와 Riverpod을 동시에 사용할 수 있다는 것을 기억하세요.*

실제로 import alias를 사용하면 두 API를 모두 사용할 수 있습니다.
이는 가독성 면에서도 좋으며 모호한 API 사용을 제거합니다.

이렇게 하려면, 코드베이스에서 각 Provider 가져오기에 대해 가져오기 별칭(alias)을 사용하는 것을 고려해 보세요.

:::info
가져오기 별칭을 효과적으로 구현하는 방법에 대한 전체 가이드가 곧 제공될 예정입니다.
:::

## `Consumer`를 바로 사용할 *필요*는 없습니다

명심해야 할 것은 [Riverpod의 `Consumer` API]를 `즉시` 사용할 필요는 없다는 점입니다.  
마이그레이션을 막 시작한 경우, [위에서 언급한 대로] `ChangeNotifierProvider`로 시작하는 것이 좋습니다.

위에서 정의한 `myNotifierProvider`를 고려해 보세요.

내부 코드가 pkg:Provider의 API에 의존하고 있을 가능성이 높으므로, 다음을 사용하여 pkg:Riverpod로 `ChangeNotifier`를 사용하기 시작하세요.
```dart
MultiProvider(
  providers: [
    ChangeNotifierProvider.value(value: ref.watch(myNotifierProvider.notifier)),
  ]
)
```

이렇게 하면 처음에 루트 위젯만 `ConsumerWidget`으로 변환하면 됩니다.  
이렇게 하면 pkg:Riverpod로 마이그레이션하는 것이 훨씬 쉬워집니다.


## 한번에 하나씩 Provider를 마이그레이션하세요

기존 앱이 있는 경우, 모든 Provider를 한꺼번에 마이그레이션하지 마세요!

장기적으로 모든 애플리케이션을 Riverpod로 이동하려고 노력해야 하지만, **자신을 지치게(burn out) 하지 마세요**.
한번에 하나의 Provider씩 처리하세요.

위의 예를 들어보겠습니다. `myNotifierProvider`를 Riverpod으로 **완전히** 마이그레이션한다는 것은 다음과 같이 작성하는 것을 의미합니다:

```dart
class MyNotifier extends Notifier<int> {
  @override
  int build() => 0;

  void increment() => state++;
}

final myNotifierProvider = NotifierProvider<MyNotifier, int>(MyNotifier.new);
```

.. 그리고 _또한_ 해당 provider가 소비되는 방식을 변경해야 합니다, 
예를 들어 이 provider에 대한 각 `context.watch`를 `ref.watch`로 변경해야 합니다.

이 작업은 시간이 다소 걸리고 오류가 발생할 수 있으므로, 한 번에 끝내려고 서두르지 마세요.

## `ProxyProvider` 마이그레이션
pkg:Provider 내에서 `ProxyProvider`는 다른 Providers의 값을 결합하는 데 사용됩니다;
빌드는 다른 Providers의 값에 따라 반응적(reactively)으로 달라집니다.

Riverpod에서는 대신 providers는 [기본적으로 컴포저블이 가능]하므로, 
`ProxyProvider`를 마이그레이션할 때 한 provider에서 다른 provider로 직접 종속성을 선언하려면 `ref.watch`를 작성하기만 하면 됩니다.

오히려 Riverpod에서 값을 결합하는 것이 더 간단하고 직관적으로 느껴질 것이므로 마이그레이션을 통해 코드를 크게 간소화할 수 있습니다.

또한 두 개 이상의 providers를 결합할 때, 복잡한 과정을 거칠 필요 없이 `ref.watch`를 하나 더 추가하기만 하면 바로 사용할 수 있습니다.

## 빠른(Eager) 초기화

Riverpod의 providers는 최종 전역(global) 변수이기 때문에 [기본적으로 지연(Lazy)] 초기화 됩니다.

시작 시 일부 워밍업 데이터나 유용한 서비스를 초기화해야 하는 경우, 가장 좋은 방법은 `MultiProvider`를 넣었던 위치에서 provider를 먼저 읽는 것입니다.

즉, Riverpod은 강제로 초기화할 수 없기 때문에, 시작 단계에서 읽고 캐시하여, 나머지 애플리케이션 내에서 필요할 때 바로 사용할 수 있도록(warm and ready) 할 수 있습니다.

pkg:Riverpod의 Provider들의 초기화에 대한 전체 가이드는 [여기에서 확인할 수 있습니다].

## 코드 생성
Riverpod을 *미래에 대비한* 방식으로 사용하려면 [코드 생성]을 권장합니다.
참고로, 메타프로그래밍(metaprogramming)이 보편화되면, 코드 생성 기능이 Riverpod의 기본값이 될 가능성이 높습니다.

안타깝게도 `@riverpod`는 `ChangeNotifierProvider`에 대한 코드를 생성할 수 없습니다.  
이 문제를 해결하기 위해 다음 유틸리티 확장 메소드(extension method)를 사용할 수 있습니다:

```dart
extension ChangeNotifierWithCodeGenExtension on Ref {
  T listenAndDisposeChangeNotifier<T extends ChangeNotifier>(T notifier) {
    notifier.addListener(notifyListeners);
    onDispose(() => notifier.removeListener(notifyListeners));
    onDispose(notifier.dispose);
    return notifier;
  }
}
```

그런 다음 다음 코드 생성 구문을 사용하여 `ChangeNotifier`를 노출할 수 있습니다:
```dart
// ignore_for_file: unsupported_provider_value
@riverpod
MyNotifier example(Ref ref) {
  return ref.listenAndDisposeChangeNotifier(MyNotifier());
}
```

"기본" 마이그레이션이 완료되면 `ChangeNotifier`를 `Notifier`로 변경할 수 있으므로 임시 확장이 필요하지 않습니다.  
앞의 사례를 예로 들면, "완전히 마이그레이션된" `Notifier`가 됩니다:

```dart
@riverpod
class MyNotifier extends _$MyNotifier {
  @override
  int build() => 0;

  void increment() => state++;
}
```

이 작업이 완료되고 코드베이스에 더 이상 `ChangeNotifierProvider`가 없다는 것이 확실해지면 임시 확장자를 완전히 제거할 수 있습니다.

코드 생성은 권장 사항이지만 *필수 사항*은 아니라는 점을 명심하세요.
마이그레이션에 대해 점진적으로 생각하는 것이 좋습니다:
한 번에 코드 생성 구문으로 *전환하면서* 마이그레이션을 구현하는 것이 과하다고 생각되면 점진적으로 마이그레이션을 고려하는 것이 *좋습니다*.

이 가이드에 따라 나중에 한 단계 더 나아가 코드생성으로 마이그레이션할 수 있습니다.

[시작하기]: /docs/introduction/getting_started
[sandbox]: https://dartpad.dev/?null_safety=true&id=ef06ab3ce0b822e6cc5db0575248e6e2
[Provider]: https://pub.dev/packages/provider
[ChangeNotifierProvider]: https://pub.dev/documentation/hooks_riverpod/latest/legacy/ChangeNotifierProvider-class.html
[코드 생성]: /docs/concepts/about_code_generation
[Riverpod의 provider들]: https://pub.dev/documentation/hooks_riverpod/latest/hooks_riverpod/Notifier-class.html
[기본적으로 컴포저블이 가능]: /docs/from_provider/motivation#combining-providers-is-hard-and-error-prone
[위에서 언급한 대로]: /docs/from_provider/quickstart#start-with-changenotifierprovider
[Riverpod의 `Consumer` API]: /docs/concepts/reading
[기본적으로 지연(Lazy)]: /docs/concepts/provider_lifecycles
[여기에서 확인할 수 있습니다]: /docs/essentials/eager_initialization
